package com.duubee.btframe.config;

import com.alibaba.fastjson.JSONObject;
import com.duubee.btframe.utils.BtEncryptUtil;
import com.duubee.btframe.utils.BtHttpClient;
import com.duubee.btframe.utils.BtStringUtil;
import com.duubee.btframe.utils.BtSystemUtil;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

@Component
public class BtFrameAuth implements ApplicationRunner,EnvironmentAware {

    private Environment env;

    @Override
    public void setEnvironment(Environment env) {
        this.env = env;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        String machineCode = getMachineCode();
        AuthBody authBody = new AuthBody();
        authBody.setMachineCode(machineCode);
        authBody.setTimestamp(new Date().getTime());

        authBody.setApplicationName(this.env.getProperty("spring.application.name"));
        authBody.setContentPath(this.env.getProperty("server.servlet.content-path"));
        String port = this.env.getProperty("server.port");
        if(BtStringUtil.isEmpty(port)){
            port = "8080";
        }
        authBody.setPort(Integer.parseInt(port));
        try {
            authBody.setIpAddress(BtSystemUtil.getLocalIpAddr());
        }finally {

        }

        //校验传输内容是否合法
        String encryptStr = MessageFormat.format("{0}|{1}|{2}|{3}|{4}|{5}",
                authBody.getApplicationName(),
                authBody.getIpAddress(),
                authBody.getTimestamp(),
                authBody.getContentPath(),
                authBody.getMachineCode(),
                authBody.getPort());

        String md5Str = BtEncryptUtil.md5(encryptStr);
        String timestamp = String.valueOf(authBody.getTimestamp());
        encryptStr = BtEncryptUtil.md5(MessageFormat.format("{0} - {1}",md5Str,timestamp));
        authBody.setEncryptStr(encryptStr);

        try {

            String result = BtHttpClient.doPost("http://dev.server.duubee.local:9100/auth/computer",JSONObject.parseObject(JSONObject.toJSONString(authBody)),null,null);

            JSONObject resultObject = JSONObject.parseObject(result);

            if(!resultObject.getBoolean("success")){
                System.err.println("Machine code：" + machineCode);
                Integer responseCode = resultObject.getInteger("code");
                switch (responseCode){
                    //鉴权服务异常
                    case 500:
                        throw new RuntimeException("Duubee authentication service abnormal");
                    //内容不合法
                    case 501:
                        throw new RuntimeException("Duubee authentication content is not legality");
                    //无权限
                    case 502:
                        throw new RuntimeException("Duubee Authentication failed，Start the service without permission");
                    //鉴权时间异常
                    case 503:
                        throw new RuntimeException("Duubee authentication time is not legality");
                    }
                System.exit(0);
            }
        }catch (Exception e){
            System.err.println("Duubee Authentication exception");
            e.printStackTrace();
            System.exit(0);
        }
    }



    private String getMachineCode(){

        Set<String> result = new HashSet<>();
        result.add(BtSystemUtil.getMac());
        result.add(BtSystemUtil.getCpuId());

        Properties props = System.getProperties();
        String javaVersion = props.getProperty("java.version");
        result.add(javaVersion);
        String javaVMVersion = props.getProperty("java.vm.version");
        result.add(javaVMVersion);
        String osVersion = props.getProperty("os.version");
        result.add(osVersion);
        result.add(String.valueOf(BtSystemUtil.getTotalPhysicalMemorySize()));

        return BtStringUtil.getSplitString(BtEncryptUtil.md5(result.toString()),"-",4);

    }



    class AuthBody implements Serializable {

        /**
         * 机器码
         */
        private String machineCode;

        /**
         * 时间戳
         */
        private Long timestamp;

        /**
         * 加密文本
         */
        private String encryptStr;

        /**
         * 项目端口号
         */
        private Integer port;

        /**
         * 上下文地址
         */
        private String contentPath;

        /**
         * ip地址
         */
        private String ipAddress;

        /**
         * 应用名
         */
        private String applicationName;


        public String getMachineCode() {
            return machineCode;
        }

        public void setMachineCode(String machineCode) {
            this.machineCode = machineCode;
        }

        public Long getTimestamp() {
            return timestamp;
        }

        public void setTimestamp(Long timestamp) {
            this.timestamp = timestamp;
        }

        public String getEncryptStr() {
            return encryptStr;
        }

        public void setEncryptStr(String encryptStr) {
            this.encryptStr = encryptStr;
        }

        public Integer getPort() {
            return port;
        }

        public void setPort(Integer port) {
            this.port = port;
        }

        public String getContentPath() {
            return contentPath;
        }

        public void setContentPath(String contentPath) {
            this.contentPath = contentPath;
        }

        public String getIpAddress() {
            return ipAddress;
        }

        public void setIpAddress(String ipAddress) {
            this.ipAddress = ipAddress;
        }

        public String getApplicationName() {
            return applicationName;
        }

        public void setApplicationName(String applicationName) {
            this.applicationName = applicationName;
        }
    }
}
